﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
using System.Threading;

public class ChatItem
{
    public bool isToMe;
    public string content;
}

public class MessageSystem : Singleton<MessageSystem>
{
    const int entriesInTrack = 100;

    Mutex readWriteLock;
    string persistentDataPath;

    public MessageSystem()
    {
        readWriteLock = new Mutex();
        persistentDataPath = Application.persistentDataPath;
    }

    public int GetMessageCount(long uid)
    {
        readWriteLock.WaitOne();
        int maxCount = 0;
        string historyDirectory = persistentDataPath + "/messageDir" + DetailPlayer.Instance.PlayerID.ToString();
        if (Directory.Exists(historyDirectory) == false)
        {
            readWriteLock.ReleaseMutex();
            return maxCount;
        }
        string historyFile = historyDirectory + "/" + uid.ToString();
        if (File.Exists(historyFile) == false)
        {
            readWriteLock.ReleaseMutex();
            return maxCount;
        }

        FileStream readStream = null;
        try
        {
            readStream = File.OpenRead(historyFile);
            byte[] intBytesArr = new byte[4];
            readStream.Read(intBytesArr, 0, 4);
            maxCount = BitConverter.ToInt32(intBytesArr, 0);
            
        }
        finally
        {
            if(readStream != null)
                readStream.Close();
            readWriteLock.ReleaseMutex();
        }
        return maxCount;
    }

    public List<ChatItem> GetMessageHistory(long uid, int from, int to)
    {
        readWriteLock.WaitOne();
        string historyDirectory = persistentDataPath + "/messageDir" + DetailPlayer.Instance.PlayerID.ToString();
        if (Directory.Exists(historyDirectory) == false)
        {
            readWriteLock.ReleaseMutex();
            return null;
        }
            
        string historyFile = historyDirectory + "/" + uid.ToString();
        if (File.Exists(historyFile) == false)
        {
            readWriteLock.ReleaseMutex();
            return null;
        }

        var readStream = File.OpenRead(historyFile);
        List<ChatItem> ret = new List<ChatItem>();
        try
        {
            byte[] intBytesArr = new byte[4];
            readStream.Read(intBytesArr, 0, 4);
            int totalCount = BitConverter.ToInt32(intBytesArr, 0);
            from = from > totalCount - 1 ? totalCount - 1: from;
            to = to > totalCount ? totalCount : to;
            if (from < 0 || from >= to)
            {
                readWriteLock.ReleaseMutex();
                return null;
            }

            //找到track和position
            int track = from / entriesInTrack;
            int positionInTrack = from - track * entriesInTrack;
            //向后找track的偏移
            for (int i = 0; i < track; i++)
            {
                readStream.Read(intBytesArr, 0, 4);
                int trackLen = BitConverter.ToInt32(intBytesArr, 0);
                readStream.Seek(trackLen, SeekOrigin.Current);
            }

            readStream.Read(intBytesArr, 0, 4);

            for (int i = from; i < to; i++)
            {
                int contentBeginOffset = 4 * entriesInTrack;
                if (positionInTrack != 0)
                {
                    readStream.Seek(4 * (positionInTrack - 1), SeekOrigin.Current);
                    readStream.Read(intBytesArr, 0, 4);
                    contentBeginOffset = BitConverter.ToInt32(intBytesArr, 0);
                }

                readStream.Read(intBytesArr, 0, 4);
                int contentEndOffset = BitConverter.ToInt32(intBytesArr, 0);
                int contentLen = contentEndOffset - contentBeginOffset;
                byte[] content = new byte[contentLen];
                readStream.Seek(contentBeginOffset - (positionInTrack + 1) * 4, SeekOrigin.Current);
                readStream.Read(content, 0, contentLen);

                ChatItem newItem = new ChatItem();
                newItem.isToMe = content[0] == 0;
                newItem.content = System.Text.Encoding.Unicode.GetString(content, 1, content.Length - 1);
                ret.Add(newItem);

                positionInTrack++;
                if (positionInTrack == entriesInTrack)
                {
                    positionInTrack = 0;
                    track++;
                    readStream.Read(intBytesArr, 0, 4);
                }
                else
                {
                    readStream.Seek(-contentEndOffset, SeekOrigin.Current);
                }
            }
        }
        finally
        {
            readStream.Close();
        }
        readWriteLock.ReleaseMutex();
        return ret;
    }

    public void WriteMessageHistory(long uid, List<ChatItem> content)
    {
        readWriteLock.WaitOne();
        string historyDirectory = persistentDataPath + "/messageDir" + DetailPlayer.Instance.PlayerID.ToString();
        if (Directory.Exists(historyDirectory) == false)
            Directory.CreateDirectory(historyDirectory);
        string historyFile = historyDirectory + "/" + uid.ToString();
        FileStream stream = null;
        if (File.Exists(historyFile) == false)
        {
            stream = File.Create(historyFile);
            stream.Write(BitConverter.GetBytes(0), 0, 4);
            stream.Close();
        }

        stream = File.Open(historyFile, FileMode.Open);
        try
        {
            //文件头,总数
            int totalCount = 0;
            byte[] intByteArr = new byte[4];
            stream.Read(intByteArr, 0, 4);
            totalCount = BitConverter.ToInt32(intByteArr, 0);
            int finalCount = totalCount + content.Count;
            stream.Seek(0, SeekOrigin.Begin);
            stream.Write(BitConverter.GetBytes(finalCount), 0, 4);

            //找到track和position
            int track = totalCount / entriesInTrack;
            int positionInTrack = totalCount - track * entriesInTrack;
            //向后找track的偏移
            for (int i = 0; i < track; i++)
            {
                stream.Read(intByteArr, 0, 4);
                int trackLen = BitConverter.ToInt32(intByteArr, 0);
                stream.Seek(trackLen, SeekOrigin.Current);
            }
            for (int i = 0; i < content.Count; i++)
            {
                byte[] contentBytes = System.Text.Encoding.Unicode.GetBytes(content[i].content);
                //写入后的track大小
                if (positionInTrack == 0)
                {
                    stream.Write(BitConverter.GetBytes(entriesInTrack * 4 + contentBytes.Length +1), 0, 4);
                    stream.Write(new byte[entriesInTrack * 4], 0, entriesInTrack * 4);
                    stream.Seek(entriesInTrack * -4, SeekOrigin.Current);
                }
                else
                {
                    stream.Read(intByteArr, 0, 4);
                    int trackLen = BitConverter.ToInt32(intByteArr, 0);
                    stream.Seek(-4, SeekOrigin.Current);
                    stream.Write(BitConverter.GetBytes(trackLen + contentBytes.Length + 1), 0, 4);
                }
                //通过下一个偏移算出长度
                int contentBeginOffset = entriesInTrack * 4;
                if (positionInTrack != 0)
                {
                    stream.Seek((positionInTrack - 1) * 4, SeekOrigin.Current);
                    stream.Read(intByteArr, 0, 4);
                    contentBeginOffset = BitConverter.ToInt32(intByteArr, 0);
                }

                int contentEndOffset = contentBytes.Length + 1 + contentBeginOffset;
                stream.Write(BitConverter.GetBytes(contentEndOffset), 0, 4);
                stream.Seek(contentBeginOffset - (positionInTrack + 1) * 4, SeekOrigin.Current);
                stream.Write(new byte[] { (byte)(content[i].isToMe ? 0: 1) }, 0, 1);
                stream.Write(contentBytes, 0, contentBytes.Length);

                positionInTrack++;
                if (positionInTrack == entriesInTrack)
                {
                    positionInTrack = 0;
                    track++;
                }
                else
                {
                    stream.Seek(-contentEndOffset - 4, SeekOrigin.Current);
                }
            }
        }
        finally
        {
            stream.Flush();
            stream.Close();
        }

        readWriteLock.ReleaseMutex();
    }
}
